package cn.javasea.rbac.shiro;

import cn.javasea.rbac.shiro.realm.CustomRealm;
import cn.javasea.rbac.shiro.session.CustomSessionManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 *@ClassName ShiroConfiguration
 *@Description TODO
 *@Author longxiaonan@163.com
 *@Date 2021/7/6 0006 10:24
 */
@Configuration
public class ShiroConfiguration {

    /**
     * 1.创建realm
     * @return
     */
    @Bean
    public CustomRealm getRealm() {
        return new CustomRealm();
    }

    /**
     * 2.创建安全管理器
     * @param realm
     * @return
     */
    @Bean
    public SecurityManager getSecurityManager(CustomRealm realm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);
        // 注册自定义的会话管理器
        securityManager.setSessionManager(sessionManager());
        // 注册自定义的安全管理器
        securityManager.setCacheManager(cacheManager());
        return securityManager;
    }

    /**
     * 3.配置shiro过滤器工厂
     *  在web程序中，shiro进行权限控制全部都是通过一组过滤器集合进行控制
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        // 1.创建过滤器工厂
        ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();
        // 2.设置安全管理器
        filterFactory.setSecurityManager(securityManager);

        // 3.通用配置（跳转的登陆页面，未授权跳转的页面）
        // 跳转的url地址
        filterFactory.setLoginUrl("/autherror?code=1");
        // 跳转到未授权的页面
        filterFactory.setUnauthorizedUrl("/autherror?code=2");

        // 4.设置过滤器集合
        Map<String, String> filterMap = new LinkedHashMap<>();
        // 当前请求地址可以匿名访问
        filterMap.put("/user/home", "anon");
        filterMap.put("/autherror", "anon");
        // 具有user-home权限才能访问
        // 不具备指定的权限，跳转到 setUnauthorizedUrl 指定的页面
        filterMap.put("/user/home", "perms[user-home]");

        // 具有 系统管理员 角色名称才能访问
        filterMap.put("/user/home", "roles[系统管理员]");

        // 当前请求地址必须认证之后可以访问
        filterMap.put("/user/**", "authc");
        filterFactory.setFilterChainDefinitionMap(filterMap);

        // 5.返回工厂
        return filterFactory;
    }

    /**
     * 4.配置shiro注解支持。如果不配置shiro的注解用不了
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    // ################## session 管理 #################
    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private Integer port;

    @Value("${spring.redis.password}")
    private String password;

    /**
     * 1.redis控制器 操作redis
     */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        redisManager.setPassword(password);
        return redisManager;
    }

    /**
     * 2.sessionDao
     */
    public RedisSessionDAO redisSessionDAO(){
        RedisSessionDAO sessionDAO = new RedisSessionDAO();
        sessionDAO.setRedisManager(redisManager());
        return sessionDAO;
    }

    /**
     * 3.会话管理器
     */
    public DefaultWebSessionManager sessionManager(){
        CustomSessionManager sessionManager = new CustomSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }

    /**
     * 4.缓存管理器
     */
    public RedisCacheManager cacheManager(){
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }
}
